package model

import (
	"errors"
	"fmt"
	"github.com/jinzhu/gorm"
)

type (
	MenuActions []*MenuAction

	MenuAction struct {
		Model
		MenuID    uint            `json:"menu_id" yaml:"-" gorm:"column:menu_id;index;not null;"`
		Slug      string          `json:"slug" yaml:"slug" gorm:"column:slug;size:255;default:'';not null;"`
		Name      string          `json:"name" yaml:"name" gorm:"column:name;size:255;default:'';not null"`
		Resources ActionResources `json:"resources" yaml:"resources" gorm:"-"`
	}
)

func (actions MenuActions) ToMap() map[string]*MenuAction {
	m := make(map[string]*MenuAction)
	for _, action := range actions {
		m[action.Slug] = action
	}
	return m
}

func GetAction(id int, tx *gorm.DB) (*MenuAction, error) {
	action := new(MenuAction)
	if err := tx.Where("id = ?", id).Find(action).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, fmt.Errorf("无法找到ID为%s的菜单动作", id)
		} else {
			return nil, err
		}
	}

	return action, nil
}

func UpdateAction(id int, change *MenuAction, tx *gorm.DB) error {
	action, err := GetAction(id, tx)
	if err != nil {
		return err
	}

	if err := tx.Model(action).Select("Name", "Slug").Updates(change).Error; err != nil {
		return err
	}
	return nil
}

func GetMenuActionsWithMenuID(menuID int) (MenuActions, error) {
	actions := make(MenuActions, 0)

	if err := db.Model(&MenuAction{}).Where("menu_id = ?", menuID).Find(&actions).Error; err != nil {
		return nil, err
	}

	for _, action := range actions {
		actions, err := GetActionResourcesWithActionID(action.ID)
		if err != nil {
			return nil, err
		}
		action.Resources = actions
	}

	return actions, nil
}

func DeleteActionsByMenuID(menuID int, tx *gorm.DB) error {
	return tx.Where("menu_id = ?", menuID).Delete(&MenuAction{}).Error
}

func DeleteAction(id uint, tx *gorm.DB) error {
	return tx.Where("id = ?", id).Delete(&MenuAction{}).Error
}

func CreateActions(menuID int, actions MenuActions, tx *gorm.DB) error {
	for _, action := range actions {
		action.MenuID = uint(menuID)
		if err := tx.Create(action).Error; err != nil {
			return err
		}

		for _, resource := range action.Resources {
			resource.ActionID = action.ID
			if err := tx.Create(resource).Error; err != nil {
				return err
			}
		}
	}

	return nil
}
